<?php

/*
 * Copyright 2015 gg.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

namespace Com\Wechat\ChatService;

/**
 * 对话服务-接收消息
 */
class ReceiveModel {

    /**
     * 微信参数（此token不是access token）
     */
    private $appid = "", $token = "", $isCrpyt = false, $aesKey = "";

    /**
     * 微信消息加解密
     */
    private $crypt = null;

    /**
     * 用于标示本类是否可用
     */
    private $flag = false;

    /**
     * 用于存储处理器
     */
    private $processer;

    /**
     * 用于存储get传入的数据
     */
    private $signature = "", $timestamp = "", $nonce = "", $echoStr = "", $msg_signature = "", $encrypt_type = "";

    /**
     * 日志模块
     */
    private $log = null;

    /**
     * 构造函数
     * @param type $appid 
     * @param type $token 不是access token
     * @param type $aesKey 如果是使用加密消息请设置此key，否则留空
     */
    public function __construct($appid, $token, $aesKey = "") {
        $this->appid = $appid;
        $this->token = $token;
        if (($this->appid != "")and ( $token != "")) {
            $this->flag = true;
        }
        if ($aesKey != "") {
            $this->isCrpyt = true;
            $this->aesKey = $aesKey;
            $this->crypt = new \Com\Wechat\Crypt\WxMsgCrypt($this->token, $this->aesKey, $this->appid);
        }
        $this->log = new \Com\Log\WriteLog();
    }

    /**
     * 用于设置消息处理器
     * @param \Com\Wechat\ChatService\MsgProcesser $processer 处理器，请传入一个实例化之后的类
     */
    public function setProcesser(&$processer) {
        if ($processer != null) {
            $this->processer = $processer;
        }
    }

    /**
     * 运行微信消息响应
     */
    public function doWechat() {
        if ($this->flag) {
            $this->getParams();
            $basic = new \Com\Wechat\ChatService\BasicModel();
            if ($basic->checkSignature($this->token, $this->signature, $this->timestamp, $this->nonce)) {
                if ($echoStr != "") {
                    $this->log->WriteLogDB("signature: $signature |timestamp: $timestamp "
                            . "|nonce: $nonce |token: " . ((APP_DEBUG) ? $this->token : "NOT ON DEBUG"), "微信接入验证成功", $this->appid);
                    echo $echoStr;
                } else {
                    $this->msgReceiver();
                }
            } else {
                $this->log->WriteLogDB("signature: $signature |timestamp: $timestamp |nonce:"
                        . " $nonce |token: " . ((APP_DEBUG) ? $this->token : "NOT ON DEBUG"), "微信接入验证失败", $this->appid);
                echo json_encode(array("flag" => FALSE, "content" => "access denied"));
            }
        } else {
            $this->log->WriteLogDB("参数设置错误", "ReceiveModelError", $this->appid);
            echo json_encode(array("flag" => FALSE, "content" => "config error"));
        }
    }

    /**
     * 接收消息，如果是加密消息就将其解密，然后分发
     */
    private function msgReceiver() {
        $postData = $GLOBALS["HTTP_RAW_POST_DATA"];
        $msgObj = null;
        if ($this->encrypt_type == "aes") {
            $msg = "";
            $decryptResult = $this->crypt->decryptMsg($this->msg_signature, $this->timestamp, $this->nonce, $postData, $msg);
            if ($decryptResult == 0) {
                $msgObj = simplexml_load_string($msg, 'SimpleXMLElement', LIBXML_NOCDATA);
                $this->msgTypeRouter($msgObj);
            } else {
                $this->log->WriteLogDB("微信消息解密错误" . (APP_DEBUG ? "|msg_signature: "
                                . "$this->msg_signature |timestamp: $this->timestamp |nonce: $this->nonce "
                                . "|data: $postData" : ""), "微信消息错误", $this->appid);
            }
        } else {
            $msgObj = simplexml_load_string($msg, 'SimpleXMLElement', LIBXML_NOCDATA);
            $this->msgTypeRouter($msgObj);
        }
    }

    /**
     * 根据消息类型分发路由
     * @param type $msgObj
     */
    private function msgTypeRouter(&$msgObj) {
        $returnMsg = "";
        switch ($msgObj->MsgType) {
            case "text":
                $returnMsg = $this->processer->processText($msgObj);
                break;
            case "image":
                $returnMsg = $this->processer->processImage($msgObj);
                break;
            case "voice":
                $returnMsg = $this->processer->processVoice($msgObj);
                break;
            case "video":
                $returnMsg = $this->processer->processVideo($msgObj);
                break;
            case "location":
                $returnMsg = $this->processer->processLocation($msgObj);
                break;
            case "link":
                $returnMsg = $this->processer->processLink($msgObj);
                break;
            default:
                break;
        }
        if (( isset($returnMsg) ) and ( $returnMsg != "")) {
            $this->sendMsg($returnMsg);
        }
    }

    /**
     * 返回消息给微信
     * @param type $msg xml字符串
     */
    private function sendMsg(&$msg) {
        if ($this->encrypt_type == "aes") {
            $nonce = mt_rand(1000000, 200000000);
            $time = time();
            $encryptResult = $this->crypt->encryptMsg($msg, $time, $nonce, $echoMsg);
            if ($encryptResult == 0) {
                echo $echoMsg;
            } else {
                $this->log->WriteLogDB("微信消息加密错误" . (APP_DEBUG ? "|timestamp: $time "
                                . "|nonce:$nonce |data: $msg" : ""), "微信消息错误", $this->appid);
            }
        } else {
            echo $msg;
        }
    }

    /**
     * 获取get传入的参数
     */
    private function getParams() {
        $this->encrypt_type = I("get.encrypt_type", "");
        $this->signature = I("get.signature", "");
        $this->timestamp = I("get.timestamp", "");
        $this->nonce = I("get.nonce", "");
        $this->echoStr = I("get.echostr", "");
        $this->msg_signature = I("get.msg_signature", "");
    }

}
